#include "idt.hpp"
#include "vga.hpp"
#include "system.hpp"
#include "cpuexceptions.hpp"

namespace system {

    extern "C"{
        void isr00();    void isr01();    void isr02();    void isr03();    void isr04();    void isr05();    void isr06();    void isr07();
        void isr08();    void isr09();    void isr0A();    void isr0B();    void isr0C();    void isr0D();    void isr0E();    void isr0F();
        void isr10();    void isr11();    void isr12();    void isr13();    void isr14();    void isr15();    void isr16();    void isr17();
        void isr18();    void isr19();    void isr1A();    void isr1B();    void isr1C();    void isr1D();    void isr1E();    void isr1F();
        void isr20();    void isr21();    void isr22();    void isr23();    void isr24();    void isr25();    void isr26();    void isr27();
        void isr28();    void isr29();    void isr2A();    void isr2B();    void isr2C();    void isr2D();    void isr2E();    void isr2F();
        void isr30();    void isr31();    void isr32();    void isr33();    void isr34();    void isr35();    void isr36();    void isr37();
        void isr38();    void isr39();    void isr3A();    void isr3B();    void isr3C();    void isr3D();    void isr3E();    void isr3F();
        void isr40();    void isr41();    void isr42();    void isr43();    void isr44();    void isr45();    void isr46();    void isr47();
        void isr48();    void isr49();    void isr4A();    void isr4B();    void isr4C();    void isr4D();    void isr4E();    void isr4F();
        void isr50();    void isr51();    void isr52();    void isr53();    void isr54();    void isr55();    void isr56();    void isr57();
        void isr58();    void isr59();    void isr5A();    void isr5B();    void isr5C();    void isr5D();    void isr5E();    void isr5F();
        void isr60();    void isr61();    void isr62();    void isr63();    void isr64();    void isr65();    void isr66();    void isr67();
        void isr68();    void isr69();    void isr6A();    void isr6B();    void isr6C();    void isr6D();    void isr6E();    void isr6F();
        void isr70();    void isr71();    void isr72();    void isr73();    void isr74();    void isr75();    void isr76();    void isr77();
        void isr78();    void isr79();    void isr7A();    void isr7B();    void isr7C();    void isr7D();    void isr7E();    void isr7F();
        void isr80();    void isr81();    void isr82();    void isr83();    void isr84();    void isr85();    void isr86();    void isr87();
        void isr88();    void isr89();    void isr8A();    void isr8B();    void isr8C();    void isr8D();    void isr8E();    void isr8F();
        void isr90();    void isr91();    void isr92();    void isr93();    void isr94();    void isr95();    void isr96();    void isr97();
        void isr98();    void isr99();    void isr9A();    void isr9B();    void isr9C();    void isr9D();    void isr9E();    void isr9F();
        void isrA0();    void isrA1();    void isrA2();    void isrA3();    void isrA4();    void isrA5();    void isrA6();    void isrA7();
        void isrA8();    void isrA9();    void isrAA();    void isrAB();    void isrAC();    void isrAD();    void isrAE();    void isrAF();
        void isrB0();    void isrB1();    void isrB2();    void isrB3();    void isrB4();    void isrB5();    void isrB6();    void isrB7();
        void isrB8();    void isrB9();    void isrBA();    void isrBB();    void isrBC();    void isrBD();    void isrBE();    void isrBF();
        void isrC0();    void isrC1();    void isrC2();    void isrC3();    void isrC4();    void isrC5();    void isrC6();    void isrC7();
        void isrC8();    void isrC9();    void isrCA();    void isrCB();    void isrCC();    void isrCD();    void isrCE();    void isrCF();
        void isrD0();    void isrD1();    void isrD2();    void isrD3();    void isrD4();    void isrD5();    void isrD6();    void isrD7();
        void isrD8();    void isrD9();    void isrDA();    void isrDB();    void isrDC();    void isrDD();    void isrDE();    void isrDF();
        void isrE0();    void isrE1();    void isrE2();    void isrE3();    void isrE4();    void isrE5();    void isrE6();    void isrE7();
        void isrE8();    void isrE9();    void isrEA();    void isrEB();    void isrEC();    void isrED();    void isrEE();    void isrEF();
        void isrF0();    void isrF1();    void isrF2();    void isrF3();    void isrF4();    void isrF5();    void isrF6();    void isrF7();
        void isrF8();    void isrF9();    void isrFA();    void isrFB();    void isrFC();    void isrFD();    void isrFE();    void isrFF();
    }


    void default_isr_f(dword x){
        dword interrupt = (*(&x - 1) - (dword)isr00) / ((dword)isr01 - (dword)isr00);
        asm volatile(""::"a"(0xBADC0DE1), "b"(interrupt), "c"(0), "d"(0), "S"(0), "D"(0));
        crash();
    }

    #define default_isr ((void(*)())default_isr_f)

    idt_entry idt_table[256];
    interrupt_handler isr[256] = {default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr,default_isr};
    idt_pointer idt_table_ptr = {sizeof(idt_table)-1,(uint32)idt_table};

    #undef default_isr

    void write_idt_entry(int index, void (*base)()){
        uint32 x = (uint32)base;
        idt_table[index] = {(uint16)(x&0xFFFF),(uint16)0x08,(uint8)0,(uint8)0x8E,(uint16)(x>>16)};
    }

    //TODO: find some solution for this.. the idt can be 'calculated' at compile time instead of run time >_<
    extern "C" void write_idt(){
        write_idt_entry(0x00,isr00);    write_idt_entry(0x01,isr01);    write_idt_entry(0x02,isr02);    write_idt_entry(0x03,isr03);
        write_idt_entry(0x04,isr04);    write_idt_entry(0x05,isr05);    write_idt_entry(0x06,isr06);    write_idt_entry(0x07,isr07);
        write_idt_entry(0x08,isr08);    write_idt_entry(0x09,isr09);    write_idt_entry(0x0A,isr0A);    write_idt_entry(0x0B,isr0B);
        write_idt_entry(0x0C,isr0C);    write_idt_entry(0x0D,isr0D);    write_idt_entry(0x0E,isr0E);    write_idt_entry(0x0F,isr0F);
        write_idt_entry(0x10,isr10);    write_idt_entry(0x11,isr11);    write_idt_entry(0x12,isr12);    write_idt_entry(0x13,isr13);
        write_idt_entry(0x14,isr14);    write_idt_entry(0x15,isr15);    write_idt_entry(0x16,isr16);    write_idt_entry(0x17,isr17);
        write_idt_entry(0x18,isr18);    write_idt_entry(0x19,isr19);    write_idt_entry(0x1A,isr1A);    write_idt_entry(0x1B,isr1B);
        write_idt_entry(0x1C,isr1C);    write_idt_entry(0x1D,isr1D);    write_idt_entry(0x1E,isr1E);    write_idt_entry(0x1F,isr1F);
        write_idt_entry(0x20,isr20);    write_idt_entry(0x21,isr21);    write_idt_entry(0x22,isr22);    write_idt_entry(0x23,isr23);
        write_idt_entry(0x24,isr24);    write_idt_entry(0x25,isr25);    write_idt_entry(0x26,isr26);    write_idt_entry(0x27,isr27);
        write_idt_entry(0x28,isr28);    write_idt_entry(0x29,isr29);    write_idt_entry(0x2A,isr2A);    write_idt_entry(0x2B,isr2B);
        write_idt_entry(0x2C,isr2C);    write_idt_entry(0x2D,isr2D);    write_idt_entry(0x2E,isr2E);    write_idt_entry(0x2F,isr2F);
        write_idt_entry(0x30,isr30);    write_idt_entry(0x31,isr31);    write_idt_entry(0x32,isr32);    write_idt_entry(0x33,isr33);
        write_idt_entry(0x34,isr34);    write_idt_entry(0x35,isr35);    write_idt_entry(0x36,isr36);    write_idt_entry(0x37,isr37);
        write_idt_entry(0x38,isr38);    write_idt_entry(0x39,isr39);    write_idt_entry(0x3A,isr3A);    write_idt_entry(0x3B,isr3B);
        write_idt_entry(0x3C,isr3C);    write_idt_entry(0x3D,isr3D);    write_idt_entry(0x3E,isr3E);    write_idt_entry(0x3F,isr3F);
        write_idt_entry(0x40,isr40);    write_idt_entry(0x41,isr41);    write_idt_entry(0x42,isr42);    write_idt_entry(0x43,isr43);
        write_idt_entry(0x44,isr44);    write_idt_entry(0x45,isr45);    write_idt_entry(0x46,isr46);    write_idt_entry(0x47,isr47);
        write_idt_entry(0x48,isr48);    write_idt_entry(0x49,isr49);    write_idt_entry(0x4A,isr4A);    write_idt_entry(0x4B,isr4B);
        write_idt_entry(0x4C,isr4C);    write_idt_entry(0x4D,isr4D);    write_idt_entry(0x4E,isr4E);    write_idt_entry(0x4F,isr4F);
        write_idt_entry(0x50,isr50);    write_idt_entry(0x51,isr51);    write_idt_entry(0x52,isr52);    write_idt_entry(0x53,isr53);
        write_idt_entry(0x54,isr54);    write_idt_entry(0x55,isr55);    write_idt_entry(0x56,isr56);    write_idt_entry(0x57,isr57);
        write_idt_entry(0x58,isr58);    write_idt_entry(0x59,isr59);    write_idt_entry(0x5A,isr5A);    write_idt_entry(0x5B,isr5B);
        write_idt_entry(0x5C,isr5C);    write_idt_entry(0x5D,isr5D);    write_idt_entry(0x5E,isr5E);    write_idt_entry(0x5F,isr5F);
        write_idt_entry(0x60,isr60);    write_idt_entry(0x61,isr61);    write_idt_entry(0x62,isr62);    write_idt_entry(0x63,isr63);
        write_idt_entry(0x64,isr64);    write_idt_entry(0x65,isr65);    write_idt_entry(0x66,isr66);    write_idt_entry(0x67,isr67);
        write_idt_entry(0x68,isr68);    write_idt_entry(0x69,isr69);    write_idt_entry(0x6A,isr6A);    write_idt_entry(0x6B,isr6B);
        write_idt_entry(0x6C,isr6C);    write_idt_entry(0x6D,isr6D);    write_idt_entry(0x6E,isr6E);    write_idt_entry(0x6F,isr6F);
        write_idt_entry(0x70,isr70);    write_idt_entry(0x71,isr71);    write_idt_entry(0x72,isr72);    write_idt_entry(0x73,isr73);
        write_idt_entry(0x74,isr74);    write_idt_entry(0x75,isr75);    write_idt_entry(0x76,isr76);    write_idt_entry(0x77,isr77);
        write_idt_entry(0x78,isr78);    write_idt_entry(0x79,isr79);    write_idt_entry(0x7A,isr7A);    write_idt_entry(0x7B,isr7B);
        write_idt_entry(0x7C,isr7C);    write_idt_entry(0x7D,isr7D);    write_idt_entry(0x7E,isr7E);    write_idt_entry(0x7F,isr7F);
        write_idt_entry(0x80,isr80);    write_idt_entry(0x81,isr81);    write_idt_entry(0x82,isr82);    write_idt_entry(0x83,isr83);
        write_idt_entry(0x84,isr84);    write_idt_entry(0x85,isr85);    write_idt_entry(0x86,isr86);    write_idt_entry(0x87,isr87);
        write_idt_entry(0x88,isr88);    write_idt_entry(0x89,isr89);    write_idt_entry(0x8A,isr8A);    write_idt_entry(0x8B,isr8B);
        write_idt_entry(0x8C,isr8C);    write_idt_entry(0x8D,isr8D);    write_idt_entry(0x8E,isr8E);    write_idt_entry(0x8F,isr8F);
        write_idt_entry(0x90,isr90);    write_idt_entry(0x91,isr91);    write_idt_entry(0x92,isr92);    write_idt_entry(0x93,isr93);
        write_idt_entry(0x94,isr94);    write_idt_entry(0x95,isr95);    write_idt_entry(0x96,isr96);    write_idt_entry(0x97,isr97);
        write_idt_entry(0x98,isr98);    write_idt_entry(0x99,isr99);    write_idt_entry(0x9A,isr9A);    write_idt_entry(0x9B,isr9B);
        write_idt_entry(0x9C,isr9C);    write_idt_entry(0x9D,isr9D);    write_idt_entry(0x9E,isr9E);    write_idt_entry(0x9F,isr9F);
        write_idt_entry(0xA0,isrA0);    write_idt_entry(0xA1,isrA1);    write_idt_entry(0xA2,isrA2);    write_idt_entry(0xA3,isrA3);
        write_idt_entry(0xA4,isrA4);    write_idt_entry(0xA5,isrA5);    write_idt_entry(0xA6,isrA6);    write_idt_entry(0xA7,isrA7);
        write_idt_entry(0xA8,isrA8);    write_idt_entry(0xA9,isrA9);    write_idt_entry(0xAA,isrAA);    write_idt_entry(0xAB,isrAB);
        write_idt_entry(0xAC,isrAC);    write_idt_entry(0xAD,isrAD);    write_idt_entry(0xAE,isrAE);    write_idt_entry(0xAF,isrAF);
        write_idt_entry(0xB0,isrB0);    write_idt_entry(0xB1,isrB1);    write_idt_entry(0xB2,isrB2);    write_idt_entry(0xB3,isrB3);
        write_idt_entry(0xB4,isrB4);    write_idt_entry(0xB5,isrB5);    write_idt_entry(0xB6,isrB6);    write_idt_entry(0xB7,isrB7);
        write_idt_entry(0xB8,isrB8);    write_idt_entry(0xB9,isrB9);    write_idt_entry(0xBA,isrBA);    write_idt_entry(0xBB,isrBB);
        write_idt_entry(0xBC,isrBC);    write_idt_entry(0xBD,isrBD);    write_idt_entry(0xBE,isrBE);    write_idt_entry(0xBF,isrBF);
        write_idt_entry(0xC0,isrC0);    write_idt_entry(0xC1,isrC1);    write_idt_entry(0xC2,isrC2);    write_idt_entry(0xC3,isrC3);
        write_idt_entry(0xC4,isrC4);    write_idt_entry(0xC5,isrC5);    write_idt_entry(0xC6,isrC6);    write_idt_entry(0xC7,isrC7);
        write_idt_entry(0xC8,isrC8);    write_idt_entry(0xC9,isrC9);    write_idt_entry(0xCA,isrCA);    write_idt_entry(0xCB,isrCB);
        write_idt_entry(0xCC,isrCC);    write_idt_entry(0xCD,isrCD);    write_idt_entry(0xCE,isrCE);    write_idt_entry(0xCF,isrCF);
        write_idt_entry(0xD0,isrD0);    write_idt_entry(0xD1,isrD1);    write_idt_entry(0xD2,isrD2);    write_idt_entry(0xD3,isrD3);
        write_idt_entry(0xD4,isrD4);    write_idt_entry(0xD5,isrD5);    write_idt_entry(0xD6,isrD6);    write_idt_entry(0xD7,isrD7);
        write_idt_entry(0xD8,isrD8);    write_idt_entry(0xD9,isrD9);    write_idt_entry(0xDA,isrDA);    write_idt_entry(0xDB,isrDB);
        write_idt_entry(0xDC,isrDC);    write_idt_entry(0xDD,isrDD);    write_idt_entry(0xDE,isrDE);    write_idt_entry(0xDF,isrDF);
        write_idt_entry(0xE0,isrE0);    write_idt_entry(0xE1,isrE1);    write_idt_entry(0xE2,isrE2);    write_idt_entry(0xE3,isrE3);
        write_idt_entry(0xE4,isrE4);    write_idt_entry(0xE5,isrE5);    write_idt_entry(0xE6,isrE6);    write_idt_entry(0xE7,isrE7);
        write_idt_entry(0xE8,isrE8);    write_idt_entry(0xE9,isrE9);    write_idt_entry(0xEA,isrEA);    write_idt_entry(0xEB,isrEB);
        write_idt_entry(0xEC,isrEC);    write_idt_entry(0xED,isrED);    write_idt_entry(0xEE,isrEE);    write_idt_entry(0xEF,isrEF);
        write_idt_entry(0xF0,isrF0);    write_idt_entry(0xF1,isrF1);    write_idt_entry(0xF2,isrF2);    write_idt_entry(0xF3,isrF3);
        write_idt_entry(0xF4,isrF4);    write_idt_entry(0xF5,isrF5);    write_idt_entry(0xF6,isrF6);    write_idt_entry(0xF7,isrF7);
        write_idt_entry(0xF8,isrF8);    write_idt_entry(0xF9,isrF9);    write_idt_entry(0xFA,isrFA);    write_idt_entry(0xFB,isrFB);
        write_idt_entry(0xFC,isrFC);    write_idt_entry(0xFD,isrFD);    write_idt_entry(0xFE,isrFE);    write_idt_entry(0xFF,isrFF);
    }

    void set_interrupt_handler(byte interrupt, interrupt_handler handler){
        isr[interrupt] = handler;
    }

    interrupt_handler get_interrupt_handler(byte interrupt){
        return isr[interrupt];
    }

}


